// Copyright (C) 1953-2022 NUDT
// Verilog module name - link_delay_accumulate
// Version: V4.1.0.20221206
// Created:
//         by - fenglin
////////////////////////////////////////////////////////////////////////////
// Description:
//         
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps

module link_delay_accumulate
(
    i_clk  ,
    i_rst_n,
    
    i_sync_step_mode                      ,

    iv_link_delay                         ,
	iv_link_delay_port_id                 ,
	i_link_delay_wr                       ,
	
	iv_csrateoffset_localnode             ,
    ov_csrateoffset_previousnode          ,
    o_csrateoffset_previousnode_wr        ,
	
    iv_data                               ,
	i_data_wr                             ,
    iv_tsmp_subtype                       ,
    
	ov_data                               ,
	o_data_wr                             
);

// I/O
// clk & rst
input                   i_clk;
input                   i_rst_n; 

input                   i_sync_step_mode;
// pkt input                      ;
input      [11:0]       iv_link_delay     ;
input      [4:0]        iv_link_delay_port_id;
input                   i_link_delay_wr      ;

input      [31:0]       iv_csrateoffset_localnode;
output reg [31:0]       ov_csrateoffset_previousnode;
output reg              o_csrateoffset_previousnode_wr;

input	   [8:0]	    iv_data        ;
input	         	    i_data_wr      ;
input      [7:0]        iv_tsmp_subtype;
// pkt output to NMA
output reg [8:0]	    ov_data        ;
output reg	            o_data_wr      ;               
//***************************************************
//               cache link delay
//***************************************************
reg    [12:0]      rv_link_delay_p0 ;
reg    [12:0]      rv_link_delay_p1 ;
reg    [12:0]      rv_link_delay_p2 ;
reg    [12:0]      rv_link_delay_p3 ;
reg    [12:0]      rv_link_delay_p4 ;
reg    [12:0]      rv_link_delay_p5 ;
reg    [12:0]      rv_link_delay_p6 ;
reg    [12:0]      rv_link_delay_p7 ;
reg    [12:0]      rv_link_delay_p8 ;
reg    [12:0]      rv_link_delay_p9 ;
reg    [12:0]      rv_link_delay_p10;
reg    [12:0]      rv_link_delay_p11;
reg    [12:0]      rv_link_delay_p12;
reg    [12:0]      rv_link_delay_p13;
reg    [12:0]      rv_link_delay_p14;
reg    [12:0]      rv_link_delay_p15;
reg    [12:0]      rv_link_delay_p16;
reg    [12:0]      rv_link_delay_p17;
reg    [12:0]      rv_link_delay_p18;
reg    [12:0]      rv_link_delay_p19;
reg    [12:0]      rv_link_delay_p20;
reg    [12:0]      rv_link_delay_p21;
reg    [12:0]      rv_link_delay_p22;
reg    [12:0]      rv_link_delay_p23;
reg    [12:0]      rv_link_delay_p24;
reg    [12:0]      rv_link_delay_p25;
reg    [12:0]      rv_link_delay_p26;
reg    [12:0]      rv_link_delay_p27;
reg    [12:0]      rv_link_delay_p28;
reg    [12:0]      rv_link_delay_p29;
reg    [12:0]      rv_link_delay_p30;
reg    [12:0]      rv_link_delay_p31;
always @(posedge i_clk or negedge i_rst_n) begin
    if(!i_rst_n)begin
        rv_link_delay_p0  <= 13'b0;
        rv_link_delay_p1  <= 13'b0;	
		rv_link_delay_p2  <= 13'b0;
		rv_link_delay_p3  <= 13'b0;
		rv_link_delay_p4  <= 13'b0;
		rv_link_delay_p5  <= 13'b0;
        rv_link_delay_p6  <= 13'b0;
		rv_link_delay_p7  <= 13'b0;
		rv_link_delay_p8  <= 13'b0;
		rv_link_delay_p9  <= 13'b0;
		rv_link_delay_p10 <= 13'b0;
        rv_link_delay_p11 <= 13'b0;
        rv_link_delay_p12 <= 13'b0;
        rv_link_delay_p13 <= 13'b0;
        rv_link_delay_p14 <= 13'b0;
        rv_link_delay_p15 <= 13'b0;
        rv_link_delay_p16 <= 13'b0;
        rv_link_delay_p17 <= 13'b0;
        rv_link_delay_p18 <= 13'b0;
        rv_link_delay_p19 <= 13'b0;
        rv_link_delay_p20 <= 13'b0;
        rv_link_delay_p21 <= 13'b0;
        rv_link_delay_p22 <= 13'b0;
        rv_link_delay_p23 <= 13'b0;
        rv_link_delay_p24 <= 13'b0;
        rv_link_delay_p25 <= 13'b0;
        rv_link_delay_p26 <= 13'b0;
        rv_link_delay_p27 <= 13'b0;
        rv_link_delay_p28 <= 13'b0;
        rv_link_delay_p29 <= 13'b0;
        rv_link_delay_p30 <= 13'b0;
        rv_link_delay_p31 <= 13'b0;
    end
    else begin
	    if(i_link_delay_wr)begin
		    case(iv_link_delay_port_id)
				5'd0 :rv_link_delay_p0  <= {1'b1,iv_link_delay};
				5'd1 :rv_link_delay_p1  <= {1'b1,iv_link_delay};
				5'd2 :rv_link_delay_p2  <= {1'b1,iv_link_delay};
				5'd3 :rv_link_delay_p3  <= {1'b1,iv_link_delay};
				5'd4 :rv_link_delay_p4  <= {1'b1,iv_link_delay};
				5'd5 :rv_link_delay_p5  <= {1'b1,iv_link_delay};
				5'd6 :rv_link_delay_p6  <= {1'b1,iv_link_delay};
				5'd7 :rv_link_delay_p7  <= {1'b1,iv_link_delay};
				5'd8 :rv_link_delay_p8  <= {1'b1,iv_link_delay};
				5'd9 :rv_link_delay_p9  <= {1'b1,iv_link_delay};
				5'd10:rv_link_delay_p10 <= {1'b1,iv_link_delay};
				5'd11:rv_link_delay_p11 <= {1'b1,iv_link_delay};
				5'd12:rv_link_delay_p12 <= {1'b1,iv_link_delay};
				5'd13:rv_link_delay_p13 <= {1'b1,iv_link_delay};
				5'd14:rv_link_delay_p14 <= {1'b1,iv_link_delay};
				5'd15:rv_link_delay_p15 <= {1'b1,iv_link_delay};
				5'd16:rv_link_delay_p16 <= {1'b1,iv_link_delay};
				5'd17:rv_link_delay_p17 <= {1'b1,iv_link_delay};
				5'd18:rv_link_delay_p18 <= {1'b1,iv_link_delay};
				5'd19:rv_link_delay_p19 <= {1'b1,iv_link_delay};
				5'd20:rv_link_delay_p20 <= {1'b1,iv_link_delay};
				5'd21:rv_link_delay_p21 <= {1'b1,iv_link_delay};
				5'd22:rv_link_delay_p22 <= {1'b1,iv_link_delay};
				5'd23:rv_link_delay_p23 <= {1'b1,iv_link_delay};
				5'd24:rv_link_delay_p24 <= {1'b1,iv_link_delay};
				5'd25:rv_link_delay_p25 <= {1'b1,iv_link_delay};
				5'd26:rv_link_delay_p26 <= {1'b1,iv_link_delay};
				5'd27:rv_link_delay_p27 <= {1'b1,iv_link_delay};
				5'd28:rv_link_delay_p28 <= {1'b1,iv_link_delay};
				5'd29:rv_link_delay_p29 <= {1'b1,iv_link_delay};
				5'd30:rv_link_delay_p30 <= {1'b1,iv_link_delay};
				5'd31:rv_link_delay_p31 <= {1'b1,iv_link_delay};
				default:rv_link_delay_p31 <= rv_link_delay_p31;
		    endcase
		end
		else begin
			rv_link_delay_p0  <= rv_link_delay_p0 ;
			rv_link_delay_p1  <= rv_link_delay_p1 ;	
			rv_link_delay_p2  <= rv_link_delay_p2 ;
			rv_link_delay_p3  <= rv_link_delay_p3 ;
			rv_link_delay_p4  <= rv_link_delay_p4 ;
			rv_link_delay_p5  <= rv_link_delay_p5 ;
			rv_link_delay_p6  <= rv_link_delay_p6 ;
			rv_link_delay_p7  <= rv_link_delay_p7 ;
			rv_link_delay_p8  <= rv_link_delay_p8 ;
			rv_link_delay_p9  <= rv_link_delay_p9 ;
			rv_link_delay_p10 <= rv_link_delay_p10;
			rv_link_delay_p11 <= rv_link_delay_p11;
			rv_link_delay_p12 <= rv_link_delay_p12;
			rv_link_delay_p13 <= rv_link_delay_p13;
			rv_link_delay_p14 <= rv_link_delay_p14;
			rv_link_delay_p15 <= rv_link_delay_p15;
			rv_link_delay_p16 <= rv_link_delay_p16;
			rv_link_delay_p17 <= rv_link_delay_p17;
			rv_link_delay_p18 <= rv_link_delay_p18;
			rv_link_delay_p19 <= rv_link_delay_p19;
			rv_link_delay_p20 <= rv_link_delay_p20;
			rv_link_delay_p21 <= rv_link_delay_p21;
			rv_link_delay_p22 <= rv_link_delay_p22;
			rv_link_delay_p23 <= rv_link_delay_p23;
			rv_link_delay_p24 <= rv_link_delay_p24;
			rv_link_delay_p25 <= rv_link_delay_p25;
			rv_link_delay_p26 <= rv_link_delay_p26;
			rv_link_delay_p27 <= rv_link_delay_p27;
			rv_link_delay_p28 <= rv_link_delay_p28;
			rv_link_delay_p29 <= rv_link_delay_p29;
			rv_link_delay_p30 <= rv_link_delay_p30;
			rv_link_delay_p31 <= rv_link_delay_p31;		
		end
	end
end
//***************************************************
//   add valid of data and delay 8 cycles
//***************************************************
reg       [71:0]       rv_data;
reg       [10:0]       rv_byte_cnt;
always @(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0)begin
        rv_data                       <= 72'h0;
		rv_byte_cnt                   <= 11'h0;
    end
    else begin
        if(i_data_wr == 1'b1)begin//write a pkt data to register
            rv_byte_cnt <= rv_byte_cnt + 1'b1;
            rv_data     <= {rv_data[62:0],iv_data};      
        end
        else begin
            rv_byte_cnt <= 11'b0;
            rv_data     <= {rv_data[62:0],9'b0};
        end
    end
end
//***************************************************
//        opensync correctionfield update
//***************************************************  
reg        [63:0]       rv_correctionfield_clock;
reg        [12:0]       rv_used_link_delay      ;
reg        [2:0]        rv_cf_update_state;  
     
localparam              IDLE_S                              = 3'd0,
                        MODIFY_MID_S                        = 3'd1,
                        GET_OSMID_S                         = 3'd2,
                        UPDATE_PTP_CF_S                     = 3'd3,
						MODIFY_CUMULATIVESCALEDRATEOFFSET_S = 3'd4,
                        TRANS_PKT_S                         = 3'd5;   
always @(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0)begin
        o_data_wr                                  <= 1'b0;
        ov_data                                    <= 9'h0; 

        ov_csrateoffset_previousnode   <= 32'b0;
        o_csrateoffset_previousnode_wr <= 1'b0;        
        rv_correctionfield_clock    <= 64'h0;
		rv_used_link_delay          <= 13'b0;
        rv_cf_update_state          <= IDLE_S;
    end
    else begin
        case(rv_cf_update_state)
            IDLE_S: begin
				rv_correctionfield_clock    <= 64'h0;	
                rv_used_link_delay          <= 13'b0;

                o_csrateoffset_previousnode_wr <= 1'b0;     				
				if(rv_data[71])begin
					o_data_wr    <= 1'b1;
					ov_data      <= rv_data[71:63];
					rv_cf_update_state <= MODIFY_MID_S;
			    end
				else begin
					o_data_wr          <= 1'b0;
				    ov_data            <= 9'h0;
					rv_cf_update_state <= IDLE_S;
				end
			end
            MODIFY_MID_S:begin//将TSMP目的MAC[11:0]修改为组播ID（12‘h700）.
				if(rv_byte_cnt == 11'd12)begin
					o_data_wr    <= 1'b1;
					ov_data      <= {rv_data[71:67],4'h7};
					rv_cf_update_state <= MODIFY_MID_S;
			    end
				else if(rv_byte_cnt == 11'd13)begin
					o_data_wr          <= 1'b1;
					ov_data            <= {rv_data[71],8'h00};
					rv_cf_update_state <= GET_OSMID_S;
				end
                else begin
					o_data_wr    <= 1'b1;
					ov_data      <= rv_data[71:63];
					rv_cf_update_state <= MODIFY_MID_S;
                end                
            end
            GET_OSMID_S:begin
				rv_correctionfield_clock    <= 64'h0;

				o_data_wr                   <= 1'b1;
				ov_data                     <= rv_data[71:63]; 				
				if(rv_byte_cnt == 11'd16)begin
				    if(iv_tsmp_subtype == 8'h1)begin //two_step/one_step,sync   
                        rv_cf_update_state <= UPDATE_PTP_CF_S;
                    end
                    else if((i_sync_step_mode == 1'b0) && (iv_tsmp_subtype == 8'h7))begin //two_step,follow_up   
                        rv_cf_update_state <= MODIFY_CUMULATIVESCALEDRATEOFFSET_S;
                    end                    
                    else if((i_sync_step_mode == 1'b1) && (iv_tsmp_subtype == 8'h1))begin //one_step,sync   
                        rv_cf_update_state <= UPDATE_PTP_CF_S;
                    end
                    else begin
                        rv_cf_update_state <= TRANS_PKT_S;
                    end
                    case(iv_data[4:0])
						5'd0 :rv_used_link_delay <= rv_link_delay_p0 ;
						5'd1 :rv_used_link_delay <= rv_link_delay_p1 ;
						5'd2 :rv_used_link_delay <= rv_link_delay_p2 ;
						5'd3 :rv_used_link_delay <= rv_link_delay_p3 ;
						5'd4 :rv_used_link_delay <= rv_link_delay_p4 ;
						5'd5 :rv_used_link_delay <= rv_link_delay_p5 ;
						5'd6 :rv_used_link_delay <= rv_link_delay_p6 ;
						5'd7 :rv_used_link_delay <= rv_link_delay_p7 ;
						5'd8 :rv_used_link_delay <= rv_link_delay_p8 ;
						5'd9 :rv_used_link_delay <= rv_link_delay_p9 ;
						5'd10:rv_used_link_delay <= rv_link_delay_p10;
						5'd11:rv_used_link_delay <= rv_link_delay_p11;
						5'd12:rv_used_link_delay <= rv_link_delay_p12;
						5'd13:rv_used_link_delay <= rv_link_delay_p13;
						5'd14:rv_used_link_delay <= rv_link_delay_p14;
						5'd15:rv_used_link_delay <= rv_link_delay_p15;
						5'd16:rv_used_link_delay <= rv_link_delay_p16;
						5'd17:rv_used_link_delay <= rv_link_delay_p17;
						5'd18:rv_used_link_delay <= rv_link_delay_p18;
						5'd19:rv_used_link_delay <= rv_link_delay_p19;
						5'd20:rv_used_link_delay <= rv_link_delay_p20;
						5'd21:rv_used_link_delay <= rv_link_delay_p21;
						5'd22:rv_used_link_delay <= rv_link_delay_p22;
						5'd23:rv_used_link_delay <= rv_link_delay_p23;
						5'd24:rv_used_link_delay <= rv_link_delay_p24;
						5'd25:rv_used_link_delay <= rv_link_delay_p25;
						5'd26:rv_used_link_delay <= rv_link_delay_p26;
						5'd27:rv_used_link_delay <= rv_link_delay_p27;
						5'd28:rv_used_link_delay <= rv_link_delay_p28;
						5'd29:rv_used_link_delay <= rv_link_delay_p29;
						5'd30:rv_used_link_delay <= rv_link_delay_p30;
						5'd31:rv_used_link_delay <= rv_link_delay_p31;
						default:rv_used_link_delay <= rv_used_link_delay;
					endcase
				end	
				else begin
					rv_used_link_delay <= rv_used_link_delay;
				end
            end			
            UPDATE_PTP_CF_S:begin//updata calculates clock of ptp 
                o_data_wr    <= 1'b1;
				if(rv_byte_cnt < 11'd62)begin
				    ov_data  <= rv_data[71:63];
                    if(rv_byte_cnt == 11'd61)begin
						rv_correctionfield_clock[63:16] <= {rv_data[61:54],rv_data[52:45],rv_data[43:36],rv_data[34:27],rv_data[25:18],rv_data[16:9]} + rv_used_link_delay[11:0];
						rv_correctionfield_clock[15:0]  <= {rv_data[7:0],iv_data[7:0]};					                           
                    end
                    else begin
						rv_correctionfield_clock <= rv_correctionfield_clock;
                    end                    
				end
				else if(rv_byte_cnt <= 11'd69)begin				
                    case(rv_byte_cnt)                           
                        11'd62:ov_data    <= rv_correctionfield_clock  [63:56];
                        11'd63:ov_data    <= rv_correctionfield_clock  [55:48];
                        11'd64:ov_data    <= rv_correctionfield_clock  [47:40];
                        11'd65:ov_data    <= rv_correctionfield_clock  [39:32];
                        11'd66:ov_data    <= rv_correctionfield_clock  [31:24];
                        11'd67:ov_data    <= rv_correctionfield_clock  [23:16];
                        11'd68:ov_data    <= rv_correctionfield_clock  [15:8];
                        11'd69:ov_data    <= rv_correctionfield_clock  [7:0];
                        default:ov_data   <= rv_data[71:63];					
                    endcase
			    end
                else begin					
                    ov_data                     <= rv_data[71:63];
                    //rv_cf_update_state          <= MODIFY_CUMULATIVESCALEDRATEOFFSET_S;
				    if((i_sync_step_mode == 1'b0) && (iv_tsmp_subtype == 8'h1))begin //two_step,sync   
                        rv_cf_update_state <= TRANS_PKT_S;
                    end
                    else if((i_sync_step_mode == 1'b0) && (iv_tsmp_subtype == 8'h7))begin //two_step,follow_up   
                        rv_cf_update_state <= MODIFY_CUMULATIVESCALEDRATEOFFSET_S;
                    end                    
                    else if((i_sync_step_mode == 1'b1) && (iv_tsmp_subtype == 8'h1))begin //one_step,sync   
                        rv_cf_update_state <= MODIFY_CUMULATIVESCALEDRATEOFFSET_S;
                    end
                    else begin
                        rv_cf_update_state <= TRANS_PKT_S;
                    end                    
                end
            end
			MODIFY_CUMULATIVESCALEDRATEOFFSET_S:begin//modify cumulativescaledrateoffset
				o_data_wr                   <= 1'b1;
				if(rv_byte_cnt <= 11'd107)begin
					ov_data                        <= rv_data[71:63];
                    o_csrateoffset_previousnode_wr <= 1'b0;                      
				end
				else if(rv_byte_cnt <= 11'd111)begin//cumulativescaledrateoffset
                    if(rv_byte_cnt == 11'd108)begin
						ov_data                     <= {1'b0,iv_csrateoffset_localnode[31:24]};

                        ov_csrateoffset_previousnode[31:24] <= rv_data[70:63];
                        o_csrateoffset_previousnode_wr      <= 1'b0;                         
                    end
                    else if(rv_byte_cnt == 11'd109)begin 
						ov_data                     <= {1'b0,iv_csrateoffset_localnode[23:16]}; 

                        ov_csrateoffset_previousnode[23:16] <= rv_data[70:63];
                        o_csrateoffset_previousnode_wr      <= 1'b0;                        
                    end
                    else if(rv_byte_cnt == 11'd110)begin 
						ov_data                     <= {1'b0,iv_csrateoffset_localnode[15:8 ]}; 

                        ov_csrateoffset_previousnode[15:8 ] <= rv_data[70:63];
                        o_csrateoffset_previousnode_wr      <= 1'b0;  						
                    end					
                    else begin
						ov_data                             <= {1'b0,iv_csrateoffset_localnode[7:0  ]};
 
                        ov_csrateoffset_previousnode[7:0  ] <= rv_data[70:63]; 
                        o_csrateoffset_previousnode_wr      <= 1'b1;
                    end					
				end
                else begin
					ov_data                             <= rv_data[71:63];
                    o_csrateoffset_previousnode_wr      <= 1'b0;                    
				    rv_cf_update_state                  <= TRANS_PKT_S;						
                end 						
			
			end 
			TRANS_PKT_S:begin
                ov_data      <= rv_data[71:63];
                o_data_wr    <= 1'b1;            
				
                o_csrateoffset_previousnode_wr      <= 1'b0;
                if(rv_data[71] == 1'b1)begin
                    rv_cf_update_state <= IDLE_S;
				end
				else begin
                    rv_cf_update_state <= TRANS_PKT_S;
				end
			end
            default:begin
				o_data_wr                     <= 1'b0;
				ov_data                       <= 9'h0;
				
				o_csrateoffset_previousnode_wr      <= 1'b0;
                rv_correctionfield_clock      <= 64'h0;
                rv_cf_update_state            <= IDLE_S;
            end
        endcase
    end
end
endmodule